package com.jbm.core.common;

import com.google.protobuf.ByteString;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * Created by root on 17-5-27.
 */
public class FaceMap
{
	public FaceMap()
	{
	}

	public FaceMap(String ifaceclass,String classpackage)
	{
		try
		{
			m_ifaceclazz = Class.forName(ifaceclass);
			m_ifaceclassname = ifaceclass;
			m_simplename = m_ifaceclazz.getSimpleName();
			m_pbclassname = classpackage + ".pb.PB" +
					m_simplename + "$" +
					m_simplename;

			m_oifaceclassname = "com.jbm.jbmsupplier.util." + m_simplename;
			m_opbclassname = "com.jbm.jbmsupplier.pb.PB" +
					m_simplename + "$" +
					m_simplename;

			m_pbclazz = Class.forName(m_pbclassname);
			m_pbbclazz = Class.forName(m_pbclassname + "$Builder");

			try
			{
				m_newbuilder = m_pbclazz.getMethod("newBuilder");
				m_pbbuild = m_pbbclazz.getMethod("build");
				m_parsefrom = m_pbclazz.getMethod("parseFrom", ByteString.class);
			}catch (Exception e)
			{
			}

			try
			{
				m_oifaceclazz = Class.forName(m_oifaceclassname);
				m_opbclazz = Class.forName(m_opbclassname);
				m_opbbclazz = Class.forName(m_opbclassname + "$Builder");
				m_onewbuilder = m_opbclazz.getMethod("newBuilder");
				m_opbbuild = m_opbbclazz.getMethod("build");
				m_oparsefrom = m_opbclazz.getMethod("parseFrom", ByteString.class);
			} catch (Exception e)
			{
			}

			m_fp2map = new HashMap<String, FacePBAtt2Map>();

			HashMap<String,Field> ifacefs = GetAllAtt(m_ifaceclazz);
			HashMap<String,Method> pbms = GetAllMethod(m_pbclazz);
			HashMap<String,Method> pbbms = GetAllMethod(m_pbbclazz);
			HashMap<String,Field> oifacefs = GetAllAtt(m_oifaceclazz);
			HashMap<String,Method> opbms = GetAllMethod(m_opbclazz);
			HashMap<String,Method> opbbms = GetAllMethod(m_opbbclazz);

			Iterator iter = ifacefs.entrySet().iterator();

			while ( iter.hasNext() )
			{
				Map.Entry entry = (Map.Entry)iter.next();

				FacePBAtt2Map fpm = new FacePBAtt2Map();

				String key = (String)entry.getKey();
				String cckey = CamelCase(key);

				m_fp2map.put(key,fpm);

				try
				{
					fpm.m_fpm.m_ifacefield = (Field) entry.getValue();
					fpm.m_fpm.m_pbhasm = pbms.get("has" + cckey);
					fpm.m_fpm.m_pbgetm = pbms.get("get" + cckey);
					fpm.m_fpm.m_pbgetcntm = pbms.get("get" + cckey + "Count");
					fpm.m_fpm.m_pbgetlstm = pbms.get("get" + cckey + "List");
					fpm.m_fpm.m_pbbsetm = pbbms.get("set" + cckey);
					fpm.m_fpm.m_pbbaddm = pbbms.get("add" + cckey);
					fpm.m_fpm.m_pbbclearm = pbbms.get("clear" + cckey);
					fpm.m_fpm.m_pbislist = fpm.m_fpm.m_pbgetlstm != null && fpm.m_fpm.m_pbgetcntm !=null;
					fpm.m_fpm.m_ifaceisarray = fpm.m_fpm.m_ifacefield.getType().isArray();
					fpm.m_fpm.m_ifaceislst = fpm.m_fpm.m_ifacefield.getType().getSimpleName().contains("List");
					fpm.m_fpm.m_ifacetype = getSType(fpm.m_fpm.m_ifacefield, fpm.m_fpm.m_ifaceisarray, fpm.m_fpm.m_ifaceislst);
					fpm.m_fpm.m_isclass = isClass(fpm.m_fpm.m_ifacetype, false);
					fpm.m_fpm.m_pbtype = fpm.m_fpm.m_pbbaddm == null ?
							fpm.m_fpm.m_pbbsetm == null ? null:
							fpm.m_fpm.m_pbbsetm.getParameterTypes()[0] :
							fpm.m_fpm.m_pbbaddm.getParameterTypes()[0];

					if (oifacefs != null)
					{
						fpm.m_ofpm.m_ifacefield = oifacefs.get(key);

						if (fpm.m_ofpm.m_ifacefield != null)
						{
							fpm.m_ofpm.m_ifaceisarray = fpm.m_ofpm.m_ifacefield.getType().isArray();
							fpm.m_ofpm.m_ifaceislst = fpm.m_ofpm.m_ifacefield.getType().getSimpleName().contains("List");
							fpm.m_ofpm.m_ifacetype = getSType(fpm.m_ofpm.m_ifacefield, fpm.m_ofpm.m_ifaceisarray, fpm.m_ofpm.m_ifaceislst);
							fpm.m_ofpm.m_isclass = isClass(fpm.m_ofpm.m_ifacetype, true);
						}
					}
					if (opbms != null)
					{
						fpm.m_ofpm.m_pbhasm = opbms.get("has" + cckey);
						fpm.m_ofpm.m_pbgetm = opbms.get("get" + cckey);
						fpm.m_ofpm.m_pbgetcntm = opbms.get("get" + cckey + "Count");
						fpm.m_ofpm.m_pbgetlstm = opbms.get("get" + cckey + "List");
						fpm.m_ofpm.m_pbislist = fpm.m_ofpm.m_pbgetlstm != null && fpm.m_ofpm.m_pbgetcntm != null;
					}
					if (opbbms != null)
					{
						fpm.m_ofpm.m_pbbsetm = opbbms.get("set" + cckey);
						fpm.m_ofpm.m_pbbaddm = opbbms.get("add" + cckey);
						fpm.m_ofpm.m_pbbclearm = opbbms.get("clear" + cckey);
						fpm.m_ofpm.m_pbtype = fpm.m_ofpm.m_pbbaddm == null ?
								fpm.m_ofpm.m_pbbsetm == null ? null:
								fpm.m_ofpm.m_pbbsetm.getParameterTypes()[0] :
								fpm.m_ofpm.m_pbbaddm.getParameterTypes()[0];
					}
				}catch (Exception e)
				{
					e.printStackTrace();
				}
			}
		}catch (Exception e)
		{
		}
	}

	private Class<?> getSType ( Field field, boolean isarray, boolean islist )
	{
		Class<?> stype = null;

		if ( isarray )
			stype = field.getType().getComponentType();

		try
		{
			if (islist)
				stype = Class.forName(
						((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0].toString().split(" ")[1]);
		}catch (Exception e)
		{
		}

		if ( stype == null )
			stype = field.getType();

		return stype;
	}

	private boolean isClass ( Class<?> type, boolean isold )
	{
		if ( isold )
			return type.getName().contains("com.jbm.jbmsupplier.util");
		else
			for (int i = 0; i < AutoCall.g_autocall.getM_iface_classes().length; i ++ )
				if( type.getName().contains(AutoCall.g_autocall.getM_iface_classes()[i]
						+ ".iface"))
					return true;

		return false;
	}

	private static String CamelCase ( String name )
	{
		char nm[] = name.toCharArray();

		for ( int i = 0; i < nm.length; i ++ )
		{
			if ( nm[i] >= 'a' && nm[i] <= 'z' && ( i == 0 || nm[i-1] == '_'||(nm[i-1]>='0'&& nm[i-1]<='9') ))
				nm[i] += ( 'A' - 'a' );
		}

		return String.valueOf(nm).replaceAll("_", "");
	}

	private HashMap<String,Field> GetAllAtt(Class<?> demo)
	{
		if ( demo == null )
			return null;

		Field[] field1 = demo.getDeclaredFields();
		Field[] field2 = demo.getFields();
		HashMap<String,Field> fields = new HashMap<String, Field>();

		int i = 0;

		for (int j = 0; i < field1.length; j++,i++)
		{
			fields.put(CamelCase(field1[j].getName()),field1[j]);
		}
		// 取得实现的接口或者父类的属性
		for (int l = 0; l < field2.length; l++,i++)
		{
			fields.put(CamelCase(field2[l].getName()),field2[l]);
		}

		return fields;
	}

	private HashMap<String,Method> GetAllMethod(Class<?> demo)
	{
		if ( demo == null )
			return null;

		Method[] method1 = demo.getDeclaredMethods();
		Method[] method2 = demo.getMethods();
		HashMap<String,Method> methods = new HashMap<String, Method>();

		for (int j = 0; j < method1.length; j++)
		{
			Class<?>[] ptypes = method1[j].getParameterTypes();

			if ( ptypes.length > 1 )
				continue;

			if ( ptypes.length == 1 &&
					ptypes[0].getSimpleName().equals("Builder") )
				continue;

			methods.put(method1[j].getName(),method1[j]);
		}

		for (int l = 0; l < method2.length; l++)
		{
			Class<?>[] ptypes = method2[l].getParameterTypes();

			if ( ptypes.length > 1 )
				continue;

			if ( ptypes.length == 1 &&
					ptypes[0].getSimpleName().equals("Builder") )
				continue;

			methods.put(method2[l].getName(),method2[l]);
		}

		return methods;
	}

	public String m_ifaceclassname;
	public String m_pbclassname;
	public String m_simplename;

	public String m_oifaceclassname;
	public String m_opbclassname;

	public Class<?> m_ifaceclazz;
	public Class<?> m_pbclazz;
	public Class<?> m_pbbclazz;
	public Class<?> m_oifaceclazz;
	public Class<?> m_opbclazz;
	public Class<?> m_opbbclazz;

	public Method m_newbuilder;
	public Method m_onewbuilder;

	public Method m_pbbuild;
	public Method m_opbbuild;

	public Method m_parsefrom;
	public Method m_oparsefrom;

	public HashMap<String,FacePBAtt2Map> m_fp2map;
}

class FacePBAtt2Map
{
	public FacePBAtt2Map()
	{
		m_fpm = new FacePBAttMap();
		m_ofpm = new FacePBAttMap();
	}

	public FacePBAttMap m_fpm;
	public FacePBAttMap m_ofpm;
}

class FacePBAttMap
{
	public FacePBAttMap()
	{
		m_ifacefield = null;
		m_pbhasm = null;
		m_pbgetm = null;
		m_pbgetcntm = null;
		m_pbgetlstm = null;
		m_pbbsetm = null;
		m_pbbaddm = null;
		m_pbbclearm = null;
		m_pbislist = false;
		m_ifaceisarray = false;
		m_ifaceislst = false;
		m_isclass = false;
	}

	public Field m_ifacefield;
	public Method m_pbhasm;
	public Method m_pbgetm;
	public Method m_pbgetcntm;
	public Method m_pbgetlstm;
	public Method m_pbbsetm;
	public Method m_pbbaddm;
	public Method m_pbbclearm;
	public Class<?> m_ifacetype;
	public Class<?> m_pbtype;
	public boolean m_pbislist;
	public boolean m_ifaceisarray;
	public boolean m_ifaceislst;
	public boolean m_isclass;
}